package alibaba;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;

public class AlibabaServerHandler implements HttpHandler {

	private static String rootDir;
	private static char fileSeprator = File.separatorChar;
	private static Listing listing;
	private static int fileEnumerator;
	private static Map<String,Map<String, DirectoryInfo>> memoryStoredDirMaps;
	private static Map<String,String> signatures;
	private static Map<String,Set<Integer> > sigToSnapshots;
	private static File listingFile;
	private static String newLine;
	//private static Map<String,>

	static public void setFileEnumerator(int inputFileEnumerator) {
		fileEnumerator = inputFileEnumerator;
		newLine = System.getProperty("line.separator");
	}

	static public void setSignatures ( Map<String,String> sigs ){
		signatures = sigs;
	}

	public static void setDirMaps(Map<String,Map<String, DirectoryInfo>> inputMemoryStoredDirMaps) {
		memoryStoredDirMaps = inputMemoryStoredDirMaps;
	}	
	static public void setListing(Listing inputListing) {
		listing = inputListing;
	}

	static void setRootDir(String inputRootDir) { 
		rootDir = inputRootDir;

		char lastChar = rootDir.charAt(rootDir.length()-1);
		if (lastChar != fileSeprator)
			rootDir += fileSeprator;
		String listingFileName = rootDir + fileSeprator + "listing.dat";
		listingFile = new File(listingFileName);
	}

	public static void setSigToSnapshots(
			Map<String, Set<Integer>> inputSigToSnapshots) {
		sigToSnapshots = inputSigToSnapshots;
	}

	public void handle(HttpExchange exchange) {

		String requestMethod = exchange.getRequestMethod();
		Headers responseHeaders = exchange.getResponseHeaders();
		Headers requestHeaders = exchange.getRequestHeaders();
		String user = "";
		user = requestHeaders.getFirst("Authorization");
		if (user == null || user == ""){
			//send bad request
			try {
				exchange.sendResponseHeaders(400, 0);
			} catch (IOException e) {
				e.printStackTrace();
			}
			return;
		}
		//handle snapshot extraction
		int snapshot = 0;


		responseHeaders.set("Content-Type", "text/plain");
		URI url = exchange.getRequestURI();
		String query = url.getQuery();
		if (query !=null){
			if (query.startsWith("snapshot")){
				try {
					snapshot = Integer.parseInt(query.substring(19));
				} catch (NumberFormatException e) {
					e.printStackTrace();
				}
			}
			else{
				try {
					if(!query.startsWith("signature")){
						snapshot = Integer.parseInt(query);
					}
				} catch (NumberFormatException e) {
				}
			}
		}
		String virtualFileName = url.getPath();
		virtualFileName = "/" + user + "/" + snapshot + virtualFileName;
		if (requestMethod.equalsIgnoreCase("GET")) {
			if (url.getQuery() != null) {
				if (query.equals("signature")) {
					returnSignature(exchange, virtualFileName);
				}
				else if (query.equals("check")) {
					check(exchange, virtualFileName,user);
				}
			}
			else if (virtualFileName.endsWith("/")) {
				list(exchange, virtualFileName,user);
			}
			else
				restoreFile(exchange, virtualFileName);
		}

		else if (requestMethod.equalsIgnoreCase("PUT")) {
			if (query !=null){
				if (query.startsWith("signature=")) {
					String signature = query.substring(10);
					if (signature == null || signature.isEmpty()){
						//send bad request
						try {
							exchange.sendResponseHeaders(400, 0);
						} catch (IOException e) {
							e.printStackTrace();
						}
						return;
					}
					tryBackupwithSignature(exchange, virtualFileName,signature, user);
				}
				else{
					if (snapshot != 0){
						createSnapshot(exchange, user, snapshot);
					}
				}
			}
			else{
				storeFile(exchange, virtualFileName, user);	
			}
		}
		else if (requestMethod.equalsIgnoreCase("DELETE")) {
			deleteSnapshot(exchange, user, snapshot);
		}
	}

	private void tryBackupwithSignature(HttpExchange exchange,
			String virtualFileName,String signature, String user) {
		try {
			//we need to back up with data
			if (!signatures.containsKey(signature)) {
				System.out.println("Input data file " + virtualFileName + " does not exist.");
				exchange.sendResponseHeaders(404, 0);
				return;
			}
			else {
				File inputFile = new File(signatures.get(signature));
				boolean isCorrupted = isFileCorrupted(inputFile, signature);
				if (isCorrupted) {
					System.out.println("Input data file " + virtualFileName + " is corrupted.");
					exchange.sendResponseHeaders(404, 0);
				}
				else if (!inputFile.exists()) {
					System.out.println("Input data file " + virtualFileName + " does not exist.");
					exchange.sendResponseHeaders(404, 0);
				}
				else if (! inputFile.canRead()) {
					System.out.println("Input data file " + virtualFileName + " is not readable.");
					exchange.sendResponseHeaders(500, 0);
					exchange.close();
				}
				//if we already have the signature, reply success and store using signature only
				else{
					String localFile = signatures.get(signature);
					File file = new File(localFile);
					byte[] fileHash = Utils.calculateSig(file);
					storeFileInServer(signature, user, virtualFileName, localFile, fileHash);

					exchange.sendResponseHeaders(200, 0);
					exchange.close();

				}
			}
		} catch (IOException e) {
			System.out.println("Got bad request");
			e.printStackTrace();
		}		
	}


	private boolean isFileCorrupted(File inputFile, String signature) {
		return !Utils.calculateSigStr(inputFile).equals(signature);
	}

	private void check(HttpExchange exchange, String virtualDirName,String user) {

		if (!virtualDirName.endsWith("/"))
			virtualDirName += "/";
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		if (memoryStoredDirMap == null){
			try {
				exchange.sendResponseHeaders(404, 0);
			} catch (IOException e) {
			}
			return;
		}
		System.out.println("check for " + virtualDirName);
		DirectoryInfo dirInfo = memoryStoredDirMap.get(virtualDirName);
		try {
			if (dirInfo == null) {
				System.out.println("Input dir " + virtualDirName + " does not exist.");
				exchange.sendResponseHeaders(404, 0);
			}
			else{ 
				exchange.sendResponseHeaders(200, 0);
				OutputStream responseBody = exchange.getResponseBody();
				OutputStreamWriter out = new OutputStreamWriter(responseBody);
				writeCheckResultsToStream(out, dirInfo, memoryStoredDirMap);

				out.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private void writeCheckResultsToStream(OutputStreamWriter out,
			DirectoryInfo dirInfo,Map<String, DirectoryInfo> memoryStoredDirMap) throws IOException {

		Set<ListingEntry> files = dirInfo.getFiles();
		for (ListingEntry fileEntry : files) {

			File file = new File(fileEntry.getLocalName());
			byte[] calculatedSig = Utils.calculateSig(file);
			byte[] storedSig = fileEntry.getFileHash();

			String outSig = Utils.zeroSig();
			
			if (calculatedSig == null)
				System.out.println("Mismatch detected: " + fileEntry.getFilename()
						+ " is missing");
			else {
				if (Arrays.equals(calculatedSig, storedSig))
					outSig = Base64.encodeBytes(calculatedSig, Base64.URL_SAFE);
				else {
					System.out.println("Signature mismatch detected for " + fileEntry.getFilename());
					System.out.println("The file's signature is " + calculatedSig);
					System.out.println("The signature in listing.dat: " + storedSig);
				}
			}
			
			String fileInfo = fileEntry.getFilename() + ", ";
			
			if (!outSig.equals(Utils.zeroSig())) {
				fileInfo += " 0";
				Set<Integer> snapshots = sigToSnapshots.get(outSig);
				if (snapshots != null)
					for (int snapshot : snapshots) {
						fileInfo += " " + snapshot;
					}
			}
			fileInfo += ", " + outSig + "\n";
			out.write(fileInfo);
		}

		Set<String> dirs = dirInfo.getSubdirectories();
		for (String dir : dirs) {			
			writeCheckResultsToStream(out, memoryStoredDirMap.get(dir),memoryStoredDirMap);
		}
	}


	private void storeFileInServer(String signature, String user,
			String virtualFileName, String localFileName, byte[] fileHash) {

		ListingEntry entry = listing.getListOfFiles().get(virtualFileName);
		//we may need to remove the old entry 
		if (entry != null){

			byte[] entryHash = entry.getFileHash();
			if (Arrays.equals(fileHash,entryHash)){
				//same file, no need to do anything
				return;
			}
		}
		ListingEntry newEntry = new ListingEntry(virtualFileName, localFileName, fileHash);
		newEntry.setOwner(user);
		if(listing.getListOfFiles().containsKey(virtualFileName)){
			listing.getListOfFiles().remove(virtualFileName);
			removeFileIfNeeded(entry.getLocalName(),entry.getFileHash());
		}
		listing.getListOfFiles().put(virtualFileName, newEntry);
		storeListing(newEntry);

	}

	private void removeFile(String localName, byte[] fileHash) {
		String sig = Utils.zeroSig();
		boolean isZeroSig = true;
		try {
			sig = Base64.encodeBytes(fileHash, Base64.URL_SAFE);
			isZeroSig = false;
		} catch (IOException e) {

			e.printStackTrace();
			isZeroSig = true;
		}
		if (!isZeroSig){
			File file = new File(localName);
			try{
				file.delete();
				signatures.remove(sig);
			}
			catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private int CheckNumOfReferencesToLocalFile(String localFileName) {
		int  numOfRefernces = 0;
		for(ListingEntry entry: listing.getListOfFiles().values()){
			if (entry.getLocalName().equalsIgnoreCase(localFileName)){
				numOfRefernces++;
			}
		}
		return numOfRefernces;
	}

	private void removeFileIfNeeded(String fileName, byte[] fileHash) {
		int refs= CheckNumOfReferencesToLocalFile(fileName);
		if (refs == 0){
			removeFile(fileName,fileHash);
		}

	}

	private void storeFile(HttpExchange exchange, String virtualFileName, String user) {
		ListingEntry entry = listing.getListOfFiles().get(virtualFileName);
		String realFileName;
		if (entry == null) {
			realFileName = rootDir + fileEnumerator;
			fileEnumerator++;
		}
		else{
			realFileName = entry.getLocalName();

			//remove from map directory
			removeListing (entry);			
			//if more then one file points to the same local file, create new file
			int refs = CheckNumOfReferencesToLocalFile(realFileName);
			if (refs > 1){
				realFileName = rootDir + fileEnumerator;
				fileEnumerator++;
			}
			else{
				removeFile(realFileName, entry.getFileHash());
			}
		}

		File outputFile = new File(realFileName);
		if(!outputFile.exists()) {
			try {
				outputFile.createNewFile();
			} catch (IOException e) {
				System.out.println("Missing persimssion to create file " + outputFile);
				e.printStackTrace();
				try {
					exchange.sendResponseHeaders(400, 0);
				} catch (IOException sendException) {
					sendException.printStackTrace();
				}
				return;
			}
		}		

		InputStream requestBody = exchange.getRequestBody();


		try {
			FileOutputStream outputStream = new FileOutputStream(outputFile);
			BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream));

			BufferedReader in = new BufferedReader(new InputStreamReader(requestBody));

			int read = 1;
			char[] buffer = new char[64 * 1024];//packet size buffer
			while (read > 0){
				read = in.read(buffer, 0, buffer.length);
				out.write(buffer, 0, read);
				if(read <  buffer.length){
					break;
				}
			}
			out.close();
			in.close();

			System.out.println(realFileName + " written to server file");

			byte[] fileHash = Utils.calculateSig(outputFile);
			entry = new ListingEntry(virtualFileName, realFileName, fileHash);
			entry.setOwner(user);
			listing.getListOfFiles().put(virtualFileName, entry);
			String signature = Base64.encodeBytes(fileHash, Base64.URL_SAFE);
			signatures.put(signature,entry.getLocalName());
			exchange.sendResponseHeaders(200, 0);
			exchange.close();
			storeListing(entry);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void removeListing(ListingEntry entry) {
		String dirName = Utils.extractVirtualDirName(entry.getFilename());
		String user = entry.getOwner();
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		if (memoryStoredDirMap == null){
			memoryStoredDirMap = new HashMap<String, DirectoryInfo>();
			memoryStoredDirMaps.put(user, memoryStoredDirMap);
		}
		DirectoryInfo dirInfo = memoryStoredDirMap.get(dirName);
		if (dirInfo == null)
			dirInfo = new DirectoryInfo(dirName, user);
		dirInfo.removeFile(entry);		
	}

	private void storeListing(ListingEntry entry) {
		String dirName = Utils.extractVirtualDirName(entry.getFilename());
		String user = entry.getOwner();
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		if (memoryStoredDirMap == null){
			memoryStoredDirMap = new HashMap<String, DirectoryInfo>();
			memoryStoredDirMaps.put(user, memoryStoredDirMap);
		}
		DirectoryInfo dirInfo = memoryStoredDirMap.get(dirName);
		if (dirInfo == null)
			dirInfo = new DirectoryInfo(dirName, user);
		dirInfo.addFile(entry);
		Utils.storeListing(listing, listingFile);
	}


	private void returnSignature(HttpExchange exchange, String virtualFileName) {
		ListingEntry entry = listing.getListOfFiles().get(virtualFileName);
		try {
			if (entry == null) {
				System.out.println("Input data file " + virtualFileName + " does not exist.");
				exchange.sendResponseHeaders(404, 0);
				return;
			}
			else {
				File inputFile = new File(entry.getLocalName());
				if (!inputFile.exists()) {
					System.out.println("Input data file " + virtualFileName + " does not exist.");
					exchange.sendResponseHeaders(404, 0);
				}
				else if (! inputFile.canRead()) {
					System.out.println("Input data file " + virtualFileName + " is not readable.");
					exchange.sendResponseHeaders(500, 0);
					exchange.close();
				}
				else{ 
					exchange.sendResponseHeaders(200, 0);
					FileInputStream inputStream = new FileInputStream(inputFile);

					byte[] fileHash = entry.getFileHash();
					String sig = Base64.encodeBytes(fileHash, Base64.URL_SAFE) + "\n";

					System.out.println("sig of file " + virtualFileName + " is " + sig);
					OutputStream responseBody = exchange.getResponseBody();
					OutputStreamWriter out = new OutputStreamWriter(responseBody);
					out.write(sig);
					out.close();
					inputStream.close();
					responseBody.close();
				}
			}
		} catch (IOException e) {
			System.out.println("Got bad request");
			e.printStackTrace();
		}
	}

	private void restoreFile(HttpExchange exchange, String virtualFileName) {
		ListingEntry entry = listing.getListOfFiles().get(virtualFileName);
		String realFileName = entry.getLocalName(); 
		File inputFile = new File(realFileName);
		try {
			if (! inputFile.exists()) {
				System.out.println("Input data file " + virtualFileName + " does not exist.");
				exchange.sendResponseHeaders(404, 0);
				exchange.close();
			}
			else if (! inputFile.canRead()) {
				System.out.println("Input data file " + virtualFileName + " is not readable.");
				exchange.sendResponseHeaders(403, 0);
				exchange.close();
			}
			else{ 
				exchange.sendResponseHeaders(200, 0);
				FileInputStream inputStream = new FileInputStream(inputFile);
				BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

				OutputStream responseBody = exchange.getResponseBody(); 
				BufferedWriter out = new BufferedWriter(new OutputStreamWriter(responseBody));

				String line;
				while ((line = in.readLine()) != null) 
					out.write(line + newLine);

				out.close();
				in.close();
				exchange.close();
			}
		} catch (IOException e) {
			System.out.println("Got bad request");
			e.printStackTrace();
		}
	}

	private void list(HttpExchange exchange, String virtualDirName, String user) {
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		if (memoryStoredDirMap == null){
			return;
		}
		DirectoryInfo dirInfo = memoryStoredDirMap.get(virtualDirName);

		try {
			if (dirInfo == null) {
				System.out.println("Input dir " + virtualDirName + " does not exist.");
				exchange.sendResponseHeaders(404, 0);
			}
			else{ 
				exchange.sendResponseHeaders(200, 0);
				Set<ListingEntry> files = dirInfo.getFiles();
				OutputStream responseBody = exchange.getResponseBody();
				OutputStreamWriter out = new OutputStreamWriter(responseBody);

				for (ListingEntry file : files) {

					String fileName = Utils.extractFileName(file.getFilename()) + "\n";
					out.write(fileName);
				}

				Set<String> dirs = dirInfo.getSubdirectories();
				for (String dirName : dirs) {

					String dirNameToWrite = Utils.extractFileName(dirName) + "\n";
					out.write(dirNameToWrite);
				}
				out.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	private void createSnapshot(HttpExchange exchange, String user, int requestedSnapshot)
	{
		//check if the user is in the snapshot's list
		if (requestedSnapshot < 1 ){
			//bad arguments
			try {
				exchange.sendResponseHeaders(500, 0);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			exchange.close();
			return;			
		}
		//copy all files to next snapshot
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		if (memoryStoredDirMap == null){
			memoryStoredDirMap = new HashMap<String, DirectoryInfo>();
			memoryStoredDirMaps.put(user, memoryStoredDirMap);
		}
		//the root snapshot dir
		String dirName = "/" + user + "/0/" ;
		String nextDirName = "/" + user + "/" + requestedSnapshot +"/";

		//check if arguments are legal
		if (memoryStoredDirMap.get(nextDirName)!= null){
			//snapshot already exist
			try {
				System.out.println("snapshot " + requestedSnapshot + " already exists");
				exchange.sendResponseHeaders(500, 0);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			exchange.close();
			return;
		}
		ArrayList<ListingEntry> entries = new ArrayList<ListingEntry> ();
		//this method fills entries with new enteries to be added
		copySubdir(dirName, nextDirName,entries,user, requestedSnapshot);
		for (ListingEntry e : entries){
			String signature = Utils.zeroSig();
			try {
				signature = Base64.encodeBytes(e.getFileHash(), Base64.URL_SAFE);
				signatures.put(signature, e.getLocalName());
				listing.getListOfFiles().put(e.getFilename(), e);
			} catch (IOException e1) {
				try {
					exchange.sendResponseHeaders(500, 0);
				} catch (IOException e2) {
					e2.printStackTrace();
				}
				exchange.close();
			}

		}
		//update listing.dat
		Utils.storeListing(listing, listingFile);

		//send success to client
		try {
			exchange.sendResponseHeaders(200, 0);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		exchange.close();
	}

	private void copySubdir(String dirName, String nextDirName,	ArrayList<ListingEntry> entries,String user, int snapshot) {
		
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		DirectoryInfo dirInfo = memoryStoredDirMap.get(dirName);
		if (dirInfo != null){
			DirectoryInfo newDirInfo = new DirectoryInfo(nextDirName, user);
			Set<ListingEntry> files = dirInfo.getFiles();
			for (ListingEntry file : files) {
				
				String sig = null;
				try {
					sig = Base64.encodeBytes(file.getFileHash(), Base64.URL_SAFE);
				} catch (IOException e) {
					e.printStackTrace();
				}
				Set<Integer> snapshots = sigToSnapshots.get(sig);
				if (snapshots == null)
					snapshots = new TreeSet<Integer>();
				snapshots.add(snapshot);
				sigToSnapshots.put(sig, snapshots);
				
				for (int snapshotInSet : snapshots) {
	
					Iterator<Integer> it = snapshots.iterator();
					int[] newSnapshots = new int[ snapshots.size() ];
					int i = 0;
					while(it.hasNext()) {
						newSnapshots[i++] = it.next();
					}

					String fileName = nextDirName + Utils.extractFileName(file.getFilename());
					if (snapshotInSet == snapshot) {
						ListingEntry newEnt = new ListingEntry(fileName, file.getLocalName(), file.getFileHash());
						newEnt.setOwner(user);
						newEnt.setSnapshotVersion(newSnapshots);
						newDirInfo.addFile(newEnt);
						entries.add(newEnt);
					}
					else {
						ListingEntry entry = getEntryFromSnapshot(fileName, snapshotInSet);
						int[] updateSnapshots = Arrays.copyOf(newSnapshots, newSnapshots.length);
						entry.setSnapshotVersion(updateSnapshots);
					}
				}
			}

			Set<String> dirs = dirInfo.getSubdirectories();
			for (String subdirName : dirs) {

				String dirNameToWrite = nextDirName + Utils.extractFileName(subdirName);
				newDirInfo.addDir(dirNameToWrite);
				copySubdir(subdirName,dirNameToWrite,entries,user,snapshot);
			}
		}
	}

	private ListingEntry getEntryFromSnapshot(String nextDirName,
			int snapshot) {

		String[] nodes = nextDirName.substring(1).split("/");
		nodes[1] = Integer.toString(snapshot);
		String fileName = ""; 
		for (String node : nodes) {
			fileName += "/" + node;
		}
		return listing.getListOfFiles().get(fileName);
	}

	private void deleteSnapshot(HttpExchange exchange, String user, int requestedSnapshot)
	{
		//the root snapshot dir
		String deleteDirName = "/" + user + "/" + requestedSnapshot + "/";

		//check if arguments are legal
		boolean isSafeToContinue = true;
		//check if the snapshot exists
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		if (memoryStoredDirMap == null){
			isSafeToContinue = false;
		}
		else{
			isSafeToContinue = memoryStoredDirMap.get(deleteDirName)!= null;
		}

		//case argument are illegal, return error
		if (!isSafeToContinue){
			try {
				exchange.sendResponseHeaders(400, 0);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			exchange.close();
			return;
		}
		//remove all files from snapshot
		ArrayList<ListingEntry> entries = new ArrayList<ListingEntry> ();

		//this method fills entries with new enteries to be deleted
		deleteSubdir(deleteDirName,entries,user);
		for (ListingEntry e : entries){
			listing.getListOfFiles().remove(e.getFilename());
		}
		//remove traces of deleted snapshot on other listing
		for (ListingEntry e : listing.getListOfFiles().values()){
						
			if (e.getOwner().equalsIgnoreCase(user)){

				String sig = null;
				try {
					sig = Base64.encodeBytes(e.getFileHash(), Base64.URL_SAFE);
				} catch (IOException excep) {
					excep.printStackTrace();
				}
				Set<Integer> snapshots = sigToSnapshots.get(sig);
				snapshots.remove(requestedSnapshot);
				if (snapshots.isEmpty())
					sigToSnapshots.remove(sig);
				else
					sigToSnapshots.put(sig, snapshots);

				int[] versions = e.getSnapshotVersion();
				if (versions != null){
					int[] newVersions = new int[versions.length - 1];
					int idx = 0;
					for (; idx < versions.length; idx++){
						if (versions[idx] == requestedSnapshot){
							break;
						}
					}
					if (idx != versions.length){
						for( int i = 0; i < idx ; i++){
							newVersions[i] = versions[i];
						}
						for( int i = idx + 1; i < newVersions.length ; i++){
							newVersions[i - 1] = versions[i];
						}
						e.setSnapshotVersion(newVersions);
					}
				}
			}
		}
		//update listing.dat
		Utils.storeListing(listing, listingFile);
		//send success to client
		try {
			exchange.sendResponseHeaders(200, 0);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		exchange.close();
	}

	private void deleteSubdir(String deleteDirName,ArrayList<ListingEntry> entries, String user) {
		Map<String, DirectoryInfo> memoryStoredDirMap = memoryStoredDirMaps.get(user);
		DirectoryInfo dirInfo = memoryStoredDirMap.get(deleteDirName);
		if (dirInfo != null){
			Set<ListingEntry> files = dirInfo.getFiles();
			for (ListingEntry file : files) {
				entries.add(file);
				dirInfo.removeFile(file);
			}
			Set<String> dirs = dirInfo.getSubdirectories();
			for (String subdirName : dirs) {
				deleteSubdir(subdirName,entries,user);
			}
			memoryStoredDirMap.remove(deleteDirName);
		}
	}
}
